/**
 * @file     static_reflect.h
 * @author   WMQ
 * @date     2024/11/1
 * @brief    static反射常用方法
 */

#ifndef STATIC_REFLECT_H
#define STATIC_REFLECT_H

#include "macro_define.h"
#include <utility>
#include <initializer_list>
#include <type_traits>

namespace StaticReflect {

template <typename T>
struct FIELDS;

// 生成变量的字段信息，字段信息包括返回变量自身引用的value()函数和返回变量自定义名称的name()函数
#define FIELD_EACH(i, arg)                          \
    template <typename T>                           \
    struct FIELD<i, T>                              \
    {                                               \
        T &obj;                                     \
        explicit FIELD(T &obj) : obj(obj) {}        \
        constexpr decltype(obj.STRIP(arg)) &value() \
        {                                           \
            return (obj.STRIP(arg));                \
        }                                           \
        static constexpr const char* name()         \
        {                                           \
            return STRING(TYPEOF(arg));             \
        }                                           \
    };

// 注册结构体要生成字段信息的变量
#define REGISTER_STRUCT(struct_name, ...)                                               \
    template <>                                                                         \
    struct StaticReflect::FIELDS<struct_name>                                           \
    {                                                                                   \
        template <int N, typename T>                                                    \
        struct FIELD;                                                                   \
        static constexpr size_t field_data_count = GET_ARG_COUNT(__VA_ARGS__);          \
        ARG(CONNECT(FOR_EACH_, GET_ARG_COUNT(__VA_ARGS__))(FIELD_EACH, 0, __VA_ARGS__)) \
    }

// 返回结构体实例的某个字段信息，如GetFieldData<0>(obj)返回obj对象的第一个变量字段信息
template <int N, typename T>
inline typename FIELDS<T>::template FIELD<N, T> GetFieldData(T &x)
{
    return typename FIELDS<T>::template FIELD<N, T>(x);
}

template <typename T>
static constexpr size_t FieldCount = FIELDS<T>::field_data_count;

template <typename T, typename = void>
struct IsHasField : std::false_type
{
};

template <typename T>
struct IsHasField<T, std::void_t<decltype(FIELDS<T>::field_data_count)>> : std::true_type
{
};

// 类型是否使用REGISTER_STRUCT宏注册字段，如IsReflected<StructA>为true或false
template <typename T>
static constexpr bool IsReflected = IsHasField<T>::value;

template <typename T, typename F, size_t... Is>
inline constexpr void ForEaching(T &obj, F f, std::index_sequence<Is...>)
{
    (void)std::initializer_list<int> {
        (f(GetFieldData<Is>(obj).name(), GetFieldData<Is>(obj).value()), 0)...};
}

// 对obj对象所有注册的变量执行一遍f方法，auto f = [](const char* field_name, auto &&field_value);
template <typename T, typename F, typename std::enable_if<IsReflected<T>, int>::type = 0>
inline constexpr void ForEach(T &obj, F f)
{
    ForEaching(obj, f, std::make_index_sequence<FIELDS<T>::field_data_count> {});
}

template <typename T, typename F, typename std::enable_if<!IsReflected<T>, int>::type = 0>
inline constexpr void ForEach(T &obj, F f)
{
}

} // namespace StaticReflect

#endif